//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2013 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _BUOLA_IO_STANDARD_H_
#define _BUOLA_IO_STANDARD_H_

#include <buola/io/ctextreader.h>
#include <buola/io/ctextwriter.h>

namespace buola {

///\addtogroup io
///@{

/// \name Standard streams
//@{

///\def BUOLA_DEBUG_LEVEL
///constant specifying the current debug level
///
///Application code wanting to override this setting should do so before
///including any buola libraries

#ifndef BUOLA_DEBUG_LEVEL
    #ifdef NDEBUG
        #define BUOLA_DEBUG_LEVEL           0
    #else
        #define BUOLA_DEBUG_LEVEL           10
    #endif
#endif

///prints the type of the given object
template<typename tType>
inline void print_type_of(tType *pObject)
{
    gOut << typeid(*pObject).name() << "\n";
}

///stream for displaying informational messages
///
///Returns a reference to the standard error stream, with no header
inline io::CTextWriter &msg_info()
{
    return gErr;
}

///stream for displaying messages to log
///
///Returns a reference to the standard error stream, with no header
inline io::CTextWriter &msg_log()
{
    return gErr;
}

///stream for displaying error messages
///
///Returns a reference to the standard error stream, after outputting a
///header to properly identify error messages
io::CTextWriter &msg_error();

///stream for displaying warning messages
///
///Returns a reference to the standard error stream, after outputting a
///header to properly identify warning messages
io::CTextWriter &msg_warn();

namespace detail {

    class CNullDebugStream {};

    template<typename tType>
    inline CNullDebugStream &operator<<(CNullDebugStream &pS,const tType&)     {   return pS;  }
        
    template<bool pPrint>
    struct CDebugStream;

    template<>
    struct CDebugStream<true>
    {
        typedef io::CTextWriter tStream;
        static tStream &Get() {   return gErr;   }
    };
        
    template<>
    struct CDebugStream<false>
    {
        typedef CNullDebugStream tStream;
        static tStream &Get()
        {
            static tStream lStream;
            return lStream;
        }
    };

/*namespace detail*/ }

///stream for displaying debug messages
///
///If pLevel is less than the current debug level, it returns a reference
///to the standard error stream. Otherwise it returns a reference to a null
///stream
template<int pLevel>
inline typename detail::CDebugStream<(pLevel<BUOLA_DEBUG_LEVEL)>::tStream &msg_debug()
{
    return detail::CDebugStream<(pLevel<BUOLA_DEBUG_LEVEL)>::Get();
}

///preprocessor macro that converts \p pText to a string
#define BUOLA_PP_TO_STRING(pText) BUOLA_PP_TO_STRING_HELPER(pText)
#define BUOLA_PP_TO_STRING_HELPER(pText) #pText

///string containing file name and line number
#define FILE_AND_LINE __FILE__ ":" BUOLA_PP_TO_STRING(__LINE__)

///prints current file and line, for following execution flow
#define TRACEPOINT ::buola::msg_log() << "-------- " << __func__ << " @ " FILE_AND_LINE " --------\n";

//@}

///@}

/*namespace buola*/ }

#endif
